
package Interfaz;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Queue;

import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;

import Coleccionables.*;
import Juego.Civil;
import Juego.Juego;
import Juego.Militar;
import Juego.Posicion;
import Objetos.*;
import Premios.*;
import Terrenos.*;
/**
 *Clase Metodos
 *existe una unica instancia de ella (Singleton)
 *@author Laurent Lisandro, Larzabal Cristian 
 */
public class Metodos {
	
	private static Metodos single=new Metodos();
	
	private Graphics2D grafico;
	private int weight;
	private int height;
	private Juego juego;
	private JLabel combustible;
	private JLabel puntaje;
	private JLabel balas;
	private DefaultListModel<String> listaColeccionables;
	
	private Metodos(){
		
	}
	/**
	 * Retorna la unica instancia de la clase
	 * @return La unica instancia de la clase
	 */
	public static synchronized Metodos get() {
		return single;
	}	
	/**
	 * Se encargar de crear un objeto Juego con los parametros tipo
	 * y la ruta del mapa, tambien llenar el SpriteStore con las
	 * imagenes de las clases y inicializa los JLabels combustible,puntaje
	 * y balas de la interfaz 
	 * @param tipo es la cadena que representa el tipo del robot
	 */
	public void cargarNivel(String tipo){
				
			juego=new Juego("/Mapas/mapa.txt",tipo);
			
		SpriteStore.get().putSprite("Imagenes/mega up.gif",Militar.class);
		SpriteStore.get().putSprite("Imagenes/mega up.gif",Civil.class);
		
		SpriteStore.get().putSprite("Imagenes/sand.png",Arena.class);			
		SpriteStore.get().putSprite("Imagenes/black.png",Color.class);
		SpriteStore.get().putSprite("Imagenes/stone.png",Concreto.class);
		SpriteStore.get().putSprite("Imagenes/water.png",Agua.class);
		SpriteStore.get().putSprite("Imagenes/box.png",Caja.class);
		SpriteStore.get().putSprite("Imagenes/fire.GIF",Fuego.class);
		SpriteStore.get().putSprite("Imagenes/street.png",Asfalto.class);
		SpriteStore.get().putSprite("Imagenes/plant.png",Planta.class);
		SpriteStore.get().putSprite("Imagenes/bullets.png",Balas.class);
		SpriteStore.get().putSprite("Imagenes/points.png",Puntos.class);
		SpriteStore.get().putSprite("Imagenes/gas.png",Nafta.class);
		SpriteStore.get().putSprite("Imagenes/cone.png",Cono.class);
		SpriteStore.get().putSprite("Imagenes/baliza.gif",Baliza.class);
		SpriteStore.get().putSprite("Imagenes/wall.png",Pared.class);
		SpriteStore.get().putSprite("Imagenes/negro.jpg",Negro.class);
		SpriteStore.get().putSprite("Imagenes/white.jpg",Blanco.class);
		combustible.setText(""+juego.Combustible());
		balas.setText(""+juego.balasRobot());
		puntaje.setText(""+juego.getPuntaje());
		paint();
	}
	/**
	 * Se encargar de avisar al juego que el robot tiene que avanzar
	 * y si pudo de graficar en panelJuego la simulacion del 
	 * robot moviendose, luego actualiza el combustible
	 */
	public synchronized void avanzar(){
		Posicion p1=juego.getPosicionRobot();		
		if(juego.puedeAvanzar(p1)){
			try{
				switch(p1.getMira()){
			
				case 'n' :{				
						for(int i=height; i>0; i--){
							if(i%25==0){
							paintSinRobot();
							SpriteStore.get().getSprite(juego.getRobot()).draw(grafico, p1.getX()*weight, (p1.getY()-1)*height+i);							
							Thread.sleep(100);
							}
						}
					break;}
		
				case 'o' :{ 
						for(int i=weight; i>0; i--){
							if(i%25==0){
								paintSinRobot();
								SpriteStore.get().getSprite(juego.getRobot()).draw(grafico, (p1.getX()-1)*weight+i, p1.getY()*height);
								Thread.sleep(100);
							}
						}
						break;}
		
				case 's' :{ 
						for(int i=height; i>0; i--){
							if(i%25==0){
							paintSinRobot();
							SpriteStore.get().getSprite(juego.getRobot()).draw(grafico, p1.getX()*weight, (p1.getY()+1)*height-i);
							Thread.sleep(100);		
							}
						}
						break;}
				case 'e' :{ 
						for(int i=weight; i>0; i--){
							if(i%25==0){
							paintSinRobot();
							SpriteStore.get().getSprite(juego.getRobot()).draw(grafico, (p1.getX()+1)*weight-i, p1.getY()*height);
							Thread.sleep(100);
							}
						}
						break;}
				}
			}
			catch (InterruptedException e) {				                  
				 e.printStackTrace();
			}
			juego.avanzar();
			combustible.setText(""+juego.Combustible());
			paint();
		}		
	}
	/**
	 * Se encargar de avisar al juego que el robot tiene que
	 *  girar a la izquierda y de graficarlo en el panelJuego
	 */
	public void girarIzquierda(){
		switch(juego.getPosicionRobot().getMira()){
			case 'n': SpriteStore.get().putSprite("Imagenes/mega left.gif",juego.getRobot().getClass());
				break;
			case 'o': SpriteStore.get().putSprite("Imagenes/mega down.gif",juego.getRobot().getClass());
			break;
			case 's': SpriteStore.get().putSprite("Imagenes/mega right.gif",juego.getRobot().getClass());
			break;
			case 'e': SpriteStore.get().putSprite("Imagenes/mega up.gif",juego.getRobot().getClass());
			break;
		}
		juego.girarIzquierda();
		
		paint();
	}
	/**
	 * Se encargar de avisar al juego que el robot tiene que
	 *  girar a la derecha y de graficarlo en el panelJuego
	 */
	public void girarDerecha(){
		switch(juego.getPosicionRobot().getMira()){
			case 'n': SpriteStore.get().putSprite("Imagenes/mega right.gif",juego.getRobot().getClass());
			break;
			case 'o': SpriteStore.get().putSprite("Imagenes/mega up.gif",juego.getRobot().getClass());
			break;
			case 's': SpriteStore.get().putSprite("Imagenes/mega left.gif",juego.getRobot().getClass());
			break;
			case 'e': SpriteStore.get().putSprite("Imagenes/mega down.gif",juego.getRobot().getClass());
			break;
			}
		juego.girarDerecha();
		
		paint();
	}
	/**
	 * recibe el Graphics de panelJuego y lo guarda, 
	 * para luego poder dibujar en el
	 * @param g Graphics del panelJuego
	 */
	public void setGraphics(Graphics g){
		grafico=(Graphics2D)g;
	}
	/**
	 * Se Encargar de dibujar todo en el grafico de panelJuego,
	 * pidiendo todos los elementos a Juego y dibujandolo con las imagenes
	 * de SpriteSore
	 */
	public void paint(){
		int x=0;
		int y=0;
		for(int i =0;i<10;i++){
			x=weight*i;
			for(int j=0;j<10;j++){
				y=height*j;
				Queue<Object> elem=juego.elements(i, j);
				while(!elem.isEmpty())	
				SpriteStore.get().getSprite(elem.poll()).draw(grafico, x, y);
			
				}
		}
		SpriteStore.get().getSprite(juego.getRobot()).draw(grafico, juego.getPosicionRobot().getX()*weight, juego.getPosicionRobot().getY()*height);
		combustible.setText(""+juego.Combustible());
		balas.setText(""+juego.balasRobot());
		puntaje.setText(""+juego.getPuntaje());
	}
	/**
	 * Se Encargar de dibujar todo menos el Robot en el grafico de panelJuego,
	 * pidiendo todos los elementos a Juego y dibujandolo con las imagenes
	 * de SpriteSore
	 */
	public void paintSinRobot(){
		int x=0;
		int y=0;
		for(int i =0;i<10;i++){
			x=weight*i;
			for(int j=0;j<10;j++){
				y=height*j;
				Queue<Object> elem=juego.elements(i, j);
				while(!elem.isEmpty())
				SpriteStore.get().getSprite(elem.poll()).draw(grafico, x, y);
			}
		}
		combustible.setText(""+juego.Combustible());
		balas.setText(""+juego.balasRobot());
		puntaje.setText(""+juego.getPuntaje());
	}
	
	/**
	 * Recibe el ancho y la altura de cada casillero de la grafica
	 * @param w ancho de casillero
	 * @param h altura de la casillero
	 */
	public void setDimension(int w,int h){
		weight=w;
		height=h;
	}
	/**
	 * Recibe los JLabels combustible, puntaje, balas y la lista donde se 
	 * muestra los coleccionables 
	 * @param c JLabel del combustible
	 * @param p JLabel del puntaje
	 * @param b JLabel de las balas
	 * @param col DefaultListModel de los coleccionables
	 */
	public void setLabels(JLabel c,JLabel p, JLabel b, DefaultListModel<String> col){
		combustible=c;
		puntaje=p;
		balas=b;
		listaColeccionables=col;
	}
	/**
	 * Consulta a Juego si terminanos y retorna el resultado
	 * @return boolean True o false si terminamos o no
	 */
	public boolean Terminamos(){
		return juego.terminamos();
	}
	/**
	 * Consulta al Juego si ganamos, devuelve true caso afirmatico, caso 
	 * contrario false
	 * @return boolean True si ganamos, False caso contrario
	 */
	public boolean ganamos(){
		return juego.ganamos();
	}
	/**
	 * Consulta al Juego el combutible del Robot y lo retorna
	 * @return int combustible del Robot
	 */
	public int Combustible(){
		return juego.Combustible();
	}
	/**
	 * Llama al metodo recolectar del juego, si recolecto algo lo agrega a la
	 * lista de coleccionables. Luego actualiza la grafica de panelJuego
	 */
	public void recolectar(){
		String aux= juego.recolectar();
		if (aux!=null)
			listaColeccionables.add(0, aux);
		paint();
	}
	/**
	 * Si tiene balas el Robot Militar crea un nuevo hilo de la 
	 * clase Disparo 
	 */
	public void disparar(){
		if(juego.balasRobot()>0){
			(new Disparo()).start();
		}
	}
	/**
	 * Llama al metodo descargar de Juego, luego actualiza la grafica de 
	 * panelJuego y tambien la lista de coleccionables
	 */
	public void descargar(){
		juego.descargar();
		paint();
		if (!listaColeccionables.isEmpty())
			listaColeccionables.removeElementAt(0);
	}
	/**
	 * Le pasa a Juego true o false, si el robot tiene que pintar o no
	 * @param p boolean true o false
	 */
	public void pintar(boolean p){
		juego.pintar(p);
	}
	/**
	 * Le pasa a Juego el color que utiliza Robot para pintar
	 * @param c String que representa el color a pintar
	 */
	public void setColor(String c){
		juego.setColor(c);
	}
	/**
	 * Retorna el Juego
	 * @return Juego
	 */
	public Juego juego(){
		return juego;
	}
	/**
	 * Retorna el ancho de la casilla
	 * @return int weight
	 */
	public int weight(){
		return weight;
	}
	/**
	 * Retorna la altura de la casilla
	 * @return int height
	 */
	public int height(){
		return height;
	}
	/**
	 * Retorna el Graphics de panelJuego
	 * @return Graphics2D de PanelJuego
	 */
	public Graphics2D grafico(){
		return grafico;
	}

}
